home *** CD-ROM | disk | FTP | other *** search
- /*
- * CLIENT routines for Simple Mail Transfer Protocol ala RFC821
- * A.D. Barksdale Garbee II, aka Bdale, N3EUA
- * Copyright 1986 Bdale Garbee, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- * Modified 14 June 1987 by P. Karn for symbolic target addresses,
- * also rebuilt locking mechanism
- * Copyright 1987 1988 David Trulli, All Rights Reserved.
- * Permission granted for non-commercial copying and use, provided
- * this notice is retained.
- */
-
- /****************************************************************************
- * $Id: smtpcli.c 1.18 94/01/04 14:10:21 ROOT_DOS Exp $
- * 29 May 92 1.2 GT mailroute (): use gateway if defined.
- * 02 Jun 92 1.3 GT Add "smtp wait" and timeout on connect () call
- * in smtp_send ().
- * 04 Jun 92 1.4 GT Make smtptick () a separate process.
- * 05 Jun 92 1.5 GT Timeout on connect () to Gateway.
- * 26 Jun 92 Paul@wolf.demon.co.uk Fixed routing for internal
- * email (doesn't go via the external gateway)
- * 13 Jul 92 1.7 GT Remove 1.6 changes.
- * 05 Aug 92 amc@beryl.demon.co.uk changed printfs to tprintf
- * 27 Aug 92 1.10 mt@kram.demon.co.uk added smtp separator
- * Dec 92 mt@kram.org don't use gateway for any mail MXed via
- * us. Add delay channel for local mail
- * Add smtp beep on|off
- * 19 Apr 93 1.16 GT If newproc () fails, reset tick flag.
- * 08 May 93 1.17 GT Fix warnings.
- * Fix "smtp list".
- * IAY Fix dot transparency as per RFC 821.
- * 07 Nov 93 1.18 GT Verbose: show "sending" progress.
- * mailroute (): cope with domain literals.
- *
- * ST NOS Version by David Nash - dnash@chaos.demon.co.uk
- *
- * __stdargs - smtp_send, smtptick_body
- * dosmtplist - call statx to fix path seperator
- *
- ****************************************************************************/
-
- #include <stdio.h>
- #include <fcntl.h>
- #ifdef ATARI
- #include <ext.h>
- #include <sys/types.h>
- #include <unistd.h>
- #endif
- #include <time.h>
- #include <setjmp.h>
- #ifdef UNIX
- #include <sys/types.h>
- #endif
- #ifdef AMIGA
- #include <stat.h>
- #else
- #include <sys/stat.h>
- #endif
- #ifdef __TURBOC__
- #include <dir.h>
- #include <io.h>
- #endif
- #include "global.h"
- #include <stdarg.h>
- #include "config.h"
- #include "domain.h"
- #include "mbuf.h"
- #include "cmdparse.h"
- #include "proc.h"
- #include "socket.h"
- #include "timer.h"
- #include "netuser.h"
- #include "smtp.h"
- #include "dirutil.h"
- #include "commands.h"
- #include "session.h"
- #include "ip.h"
-
- static struct timer Smtpcli_t;
- static int32 Gateway;
- static int32 Delaytime = 0;
- int near smtpverbose = 1;
- char *near smtp_separator = NULL;
- int near are_we_an_mx;
-
- static unsigned short Smtptrace = 0; /* used for trace level */
- static int dosmtptrace __ARGS ((int argc, char *argv[], void *p));
-
- static unsigned short Smtpmaxcli = MAXSESSIONS; /* the max client connections
- * allowed */
- static int Smtpsessions = 0; /* number of client connections currently open */
- static int Smtpbatch;
- int near Smtpmode = 0;
- int near Smtpbeep = 0;
-
- int32 near connect_wait_val = 60000L; /* default connection timeout */
-
- static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client
- * sessions */
-
- static void del_job __ARGS ((struct smtp_job * jp));
- static void del_session __ARGS ((struct smtpcli * cb));
- static int dogateway __ARGS ((int argc, char *argv[], void *p));
- static int doseparator __ARGS ((int argc, char *argv[], void *p));
- static int dosmtpmaxcli __ARGS ((int argc, char *argv[], void *p));
- static int dotimer __ARGS ((int argc, char *argv[], void *p));
- static int dodelay __ARGS ((int argc, char *argv[], void *p));
- static int dowait __ARGS ((int argc, char *argv[], void *p));
- static int dosmtpkill __ARGS ((int argc, char *argv[], void *p));
- static int dosmtplist __ARGS ((int argc, char *argv[], void *p));
- static int dobatch __ARGS ((int argc, char *argv[], void *p));
- static int dobeep __ARGS ((int argc, char *argv[], void *p));
- static void execjobs __ARGS ((void));
- static int getresp __ARGS ((struct smtpcli * ftp, int mincode));
- static void logerr __ARGS ((struct smtpcli * cb, char *line));
- static struct smtpcli *lookup __ARGS ((int32 destaddr));
- static struct smtpcli *newcb __ARGS ((void));
- static int next_job __ARGS ((struct smtpcli * cb));
- static void retmail __ARGS ((struct smtpcli * cb));
- static void sendcmd __ARGS ((struct smtpcli * cb, char *fmt,...));
- static int smtpsendfile __ARGS ((struct smtpcli * cb));
- static int setsmtpmode __ARGS ((int argc, char *argv[], void *p));
- static struct smtp_job *setupjob __ARGS ((struct smtpcli * cb, char *id, char *from));
- static void __stdargs smtp_send __ARGS ((int unused, void *cb1, void *p));
- static int smtpkick __ARGS ((int argc, char *argv[], void *p));
- static void __stdargs smtptick_body __ARGS ((int unused, void *t, void *p));
- static int doverbose __ARGS ((int argc, char *argv[], void *p));
- static int should_enter_delay __ARGS ((struct smtpcli * cb));
- static int explock __ARGS ((char *dir, char *pre, char *suf, int32 age));
-
- static struct cmds Smtpcmds[] = {
- {"batch", dobatch, 0, 0, NULLCHAR},
- {"beep", dobeep, 0, 0, NULLCHAR},
- {"delay", dodelay, 0, 0, NULLCHAR},
- {"gateway", dogateway, 0, 0, NULLCHAR},
- {"kick", smtpkick, 0, 0, NULLCHAR},
- {"kill", dosmtpkill, 0, 2, "kill <jobnumber>"},
- {"list", dosmtplist, 0, 0, NULLCHAR},
- {"maxclients", dosmtpmaxcli, 0, 0, NULLCHAR},
- {"mode", setsmtpmode, 0, 0, NULLCHAR},
- {"separator", doseparator, 0, 0, NULLCHAR},
- {"timer", dotimer, 0, 0, NULLCHAR},
- {"trace", dosmtptrace, 0, 0, NULLCHAR},
- {"wait", dowait, 0, 0, NULLCHAR},
- {"verbose", doverbose, 0, 0, NULLCHAR}, /* Actually for Server */
- {NULLCHAR},
- };
-
-
- int dosmtp(int argc, char *argv[], void *p)
- {
- return subcmd (Smtpcmds, argc, argv, p);
- }
-
-
- static int dobatch(int argc, char *argv[], void *p)
- {
- return setbool (&Smtpbatch, "SMTP batching", argc, argv);
- }
-
-
- static int dobeep(int argc, char *argv[], void *p)
- {
- return setbool (&Smtpbeep, "SMTP beep on delivery", argc, argv);
- }
-
-
- static int dosmtpmaxcli(int argc, char *argv[], void *p)
- {
- return setshort (&Smtpmaxcli, "Max clients", argc, argv);
- }
-
-
- static int setsmtpmode(int argc, char *argv[], void *p)
- {
- if (argc < 2) {
- tprintf ("smtp mode: %s\n", (Smtpmode & QUEUE) ? "queue" : "route");
- }
- else {
- switch (*argv[1]) {
- case 'q':
- Smtpmode |= QUEUE;
- break;
- case 'r':
- Smtpmode &= ~QUEUE;
- break;
- default:
- tprintf ("Usage: smtp mode [queue | route]\n");
- break;
- }
- }
-
- return 0;
- }
-
-
- static int dogateway(int argc, char *argv[], void *p)
- {
- int32 n;
-
- if (argc < 2)
- tprintf ("%s\n", inet_ntoa (Gateway));
- else
- if ((n = resolve (argv[1])) == 0) {
- tprintf (Badhost, argv[1]);
- return 1;
- }
- else
- Gateway = n;
- log(-1, "dogateway: resolve gateway = %x ", (void *)Gateway); /* DEBUG */
-
- return 0;
- }
-
-
- static int doseparator(int argc, char *argv[], void *p)
- {
- int i;
- char *t;
-
- if (argc < 2) {
- if (smtp_separator) {
- log(-1, "doseparator: free smtp_separator = %x ",(void *)smtp_separator); /* DEBUG */
- free(smtp_separator);
- }
-
- smtp_separator = NULL;
- }
- else {
- t = malloc(81);
- log(-1, "doseperator: malloc t = %x ", (void *)t); /* DEBUG */
- if (t == NULL)
- return 1;
-
- t[0] = '\0';
- for (i = 1; i < argc; i++) {
- strcat (t, argv[i]);
- if (i < (argc - 1))
- strcat (t, " ");
-
- }
- if ((smtp_separator = malloc(strlen (t) + 1)) == NULL) {
- log(-1, "doseperator: free t = %x ", (void *)t); /* DEBUG */
- free(t);
- return 1;
- }
- log(-1, "doseperator: malloc smtp_separator = %x ", (void *)smtp_separator); /* DEBUG */
-
- strcpy(smtp_separator, t);
- log(-1, "doseperator: free t = %x ", (void *)t); /* DEBUG */
- free(t);
- }
-
- return 0;
- }
-
-
- static int dosmtptrace(int argc, char *argv[], void *p)
- {
- return setshort (&Smtptrace, "SMTP tracing", argc, argv);
- }
-
-
- /* list jobs wating to be sent in the mqueue */
-
- static int dosmtplist (int argc, char *argv[], void *p)
- {
- char tstring[80];
- char line[20];
- char host[LINELEN];
- char to[LINELEN];
- char from[LINELEN];
- char *cp;
- char status;
- struct stat stbuf;
- struct tm *tminfo;
- FILE *fp;
-
- int statx(const char *, struct stat *);
-
- Current->flowmode = 1; /* Enable the more mechanism */
- tprintf ("S Job Size Date Time Host From\n");
- filedir (Mailqueue, 0, line);
- while (line[0] != '\0') {
- (void) sprintf (tstring, "%s/%s", Mailqdir, line);
- if ((fp = fopen (tstring, READ_TEXT)) == NULLFILE) {
- tprintf ("Can't open %s: %s\n", tstring, sys_errlist[errno]);
- pwait (NULL);
- filedir (Mailqueue, 1, line);
- continue;
- }
-
- if ((cp = strrchr (line, '.')) != NULLCHAR)
- *cp = '\0';
-
- (void) sprintf (tstring, "%s/%s.lck", Mailqdir, line);
- if (access (tstring, 0))
- status = ' ';
- else
- status = 'L';
-
- /* Now see if it's in delay */
- if (status == ' ') {
- sprintf (tstring, "%s/%s.dly", Mailqdir, line);
- if (!access (tstring, 0))
- status = 'D';
-
- }
-
- (void) sprintf (tstring, "%s/%s.txt", Mailqdir, line);
- if (statx (tstring, &stbuf) == -1) { /* ATARI statx to fix path sep */
- tprintf ("Can't stat %s: %s\n", tstring, sys_errlist[errno]);
- pwait (NULL);
- filedir (Mailqueue, 1, line);
- continue;
- }
-
- tminfo = localtime (&stbuf.st_ctime);
- fgets (host, sizeof (host), fp);
- rip (host);
- fgets (from, sizeof (from), fp);
- rip (from);
- tprintf ("%c %7s %7ld %02d/%02d %02d:%02d %-20s %s\n ",
- status, line, stbuf.st_size,
- tminfo->tm_mon + 1,
- tminfo->tm_mday,
- tminfo->tm_hour,
- tminfo->tm_min,
- host, from);
- while (fgets (to, sizeof (to), fp) != NULLCHAR) {
- rip (to);
- tprintf ("%s ", to);
- }
-
- tprintf ("\n");
- (void) fclose (fp);
- pwait (NULL);
- filedir (Mailqueue, 1, line);
- }
-
- Current->flowmode = 0;
- return 0;
- }
-
-
- /* dosmtpkill - kill a job in the mqueue */
-
- static int dosmtpkill(int argc, char *argv[], void *p)
- {
- char s[SLINELEN];
- char *cp, c;
-
- sprintf (s, "%s/%s.lck", Mailqdir, argv[1]);
- cp = strrchr (s, '.');
- if (!access (s, 0)) {
- Current->ttystate.echo = Current->ttystate.edit = 0;
- c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ", 0);
- Current->ttystate.echo = Current->ttystate.edit = 1;
- if (c != 'y')
- return 0;
-
- (void)unlink(s);
- }
-
- strcpy(cp, ".wrk");
- if (unlink(s))
- tprintf("Job id %s not found\n", argv[1]);
-
- strcpy(cp, ".txt");
- (void)unlink(s);
- strcpy(cp, ".dly");
- (void)unlink(s);
-
- return 0;
- }
-
-
- /* dotimer - Set outbound spool scan interval */
-
- static int dotimer(int argc, char *argv[], void *p)
- {
- if (argc < 2) {
- tprintf ("%lu/%lu\n",
- read_timer (&Smtpcli_t) / 1000L,
- dur_timer (&Smtpcli_t) / 1000L);
- return 0;
- }
-
- Smtpcli_t.func = (void (*) ()) smtptick; /* what to call on timeout */
- Smtpcli_t.arg = NULL; /* dummy value */
- set_timer (&Smtpcli_t, atol (argv[1]) * 1000L); /* set timer duration */
- start_timer (&Smtpcli_t); /* and fire it up */
-
- return 0;
- }
-
-
- /* dodelay - Set delay channel time */
-
- static int dodelay(int argc, char *argv[], void *p)
- {
- if (argc < 2) {
- tprintf ("%lu\n", Delaytime);
- return 0;
- }
-
- Delaytime = atol (argv[1]);
-
- return 0;
- }
-
-
- /* dowait - Displays or sets the connection wait timeout. */
-
- static int dowait(int argc, char *argv[], void *p)
- {
- if (argc < 2) {
- tprintf ("smtp connection timeout: %lu\n", connect_wait_val / 1000L);
- return (0);
- }
-
- connect_wait_val = atol (argv[1]) * 1000L; /* set timeout */
-
- return (0);
- }
-
-
- static int smtpkick(int argc, char *argv[], void *p)
- {
- int32 addr = 0;
-
- if (argc > 1 && (addr = resolve (argv[1])) == 0) {
- tprintf (Badhost, argv[1]);
- return 1;
- }
- log(-1, "smtpkick: resolve addr = %x ", (void *)addr); /* DEBUG */
- smtptick ((void *) addr);
- return 0;
- }
-
-
- /* This is the routine that gets called every so often to do outgoing
- * mail processing. When called with a null argument, it runs the entire
- * queue; if called with a specific non-zero IP address from the remote
- * kick server, it only starts up sessions to that address.
- */
-
- static char smtptick_running = 0;
-
- int smtptick(void *t) {
-
- if (smtptick_running != 0)
- return (0);
-
- smtptick_running = 1;
- if (newproc ("smtp_tick", 1024, smtptick_body, 0, t, NULL, 0) == NULLPROC) {
- start_timer (&Smtpcli_t); /* wait a while */
- smtptick_running = 0;
- }
-
- return (0);
- }
-
-
- static void __stdargs smtptick_body (int unused, void *t, void *p)
- {
- struct smtpcli *cb;
- struct smtp_job *jp;
- struct list *ap;
- char tmpstring[LINELEN], wfilename[13], prefix[9];
- char from[LINELEN], to[LINELEN];
- char *cp, *cp1;
- int32 destaddr, target, num_files;
- FILE *wfile;
-
- target = (int32) t;
-
- if (Smtptrace > 5)
- tprintf ("smtp daemon entered, target = %s\n", inet_ntoa (target));
-
- if (availmem () < Memthresh) {
- /* Memory is tight, don't do anything */
- /* Restart timer */
- start_timer (&Smtpcli_t);
- smtptick_running = 0;
- return;
- }
-
- /* First see how many there are now */
-
- num_files = 0;
- for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0';
- filedir (Mailqueue, 1, wfilename))
- num_files++;
-
- /* Try to deal with that many messages, no more or we may loop forever */
-
- for (filedir (Mailqueue, 0, wfilename); wfilename[0] != '\0' && num_files--;
- filedir (Mailqueue, 1, wfilename)) {
-
- /* save the prefix of the file name which it job id */
- cp = wfilename;
- cp1 = prefix;
- while (*cp && *cp != '.')
- *cp1++ = *cp++;
-
- *cp1 = '\0';
-
- /* lock this file from the smtp daemon */
- if (mlock (Mailqdir, prefix))
- continue;
-
- /* Try to bring the job outof delay (in case it's in delay) */
-
- explock (Mailqdir, prefix, "dly", Delaytime);
-
- /* Check that it's not in delay */
- if (mlock_suffix (Mailqdir, prefix, "dly")) {
- rmlock (Mailqdir, prefix);
- continue;
- }
- else
- rmlock_suffix (Mailqdir, prefix, "dly");
-
- sprintf (tmpstring, "%s/%s", Mailqdir, wfilename);
- if ((wfile = fopen (tmpstring, READ_TEXT)) == NULLFILE) {
- /* probably too many open files */
- (void) rmlock (Mailqdir, prefix);
- /* continue to next message. The failure may be temporary */
- continue;
- }
-
- (void) fgets (tmpstring, LINELEN, wfile);/* read target host */
- rip (tmpstring);
-
- if ((destaddr = mailroute (tmpstring, Ip_addr)) == 0) {
- fclose (wfile);
- tprintf ("** smtp: Unknown address %s\n", tmpstring);
- (void) rmlock (Mailqdir, prefix);
- continue;
- }
-
- if (target != 0 && destaddr != target) {
- fclose (wfile);
- (void) rmlock (Mailqdir, prefix);
- continue; /* Not the proper target of a kick */
- }
-
- if ((cb = lookup (destaddr)) == NULLSMTPCLI) {
- /* there are enough processes running already */
- if (Smtpsessions >= Smtpmaxcli) {
- if (Smtptrace)
- tprintf ("smtp daemon: too many processes\n");
- fclose (wfile);
- (void) rmlock (Mailqdir, prefix);
- break;
- }
-
- if ((cb = newcb()) == NULLSMTPCLI) {
- fclose(wfile);
- (void)rmlock(Mailqdir, prefix);
- break;
- }
-
- cb->ipdest = destaddr;
- cb->destname = strdup(tmpstring); /* implicit malloc */
- log(-1, "smtptick_body: strdup cb->destname = %x ", (void *)cb->destname); /* DEBUG */
- }
- else {
- if (cb->lock) {
- /* This system is already is sending mail lets not
- * interfere with its send queue. */
- fclose (wfile);
- (void) rmlock (Mailqdir, prefix);
- continue;
- }
- }
-
- (void) fgets (from, LINELEN, wfile); /* read from */
- rip (from);
- if ((jp = setupjob(cb, prefix, from)) == NULLJOB) {
- fclose(wfile);
- rmlock(Mailqdir, prefix);
- del_session(cb);
- break;
- }
-
- while (fgets(to, LINELEN, wfile) != NULLCHAR) {
- rip(to);
- if (addlist(&jp->to, to, DOMAIN) == NULLLIST) {
- fclose(wfile);
- del_session(cb);
- }
- log(-1, "smpttick_body: addlist jp->to = %x ", jp->to); /* DEBUG */
- log(-1, "smpttick_body: addlist jp->to->val = %x ", jp->to->val); /* DEBUG */
-
- }
- fclose(wfile);
-
- if (Smtptrace > 1) {
- tprintf("queue job %s From: %s To:", prefix, from);
- for (ap = jp->to; ap != NULLLIST; ap = ap->next)
- tprintf(" %s", ap->val);
- tprintf ("\n");
- }
-
- if (smtpverbose != 0 && Smtptrace <= 1) {
- tprintf ("Sending %s From: %s To:", prefix, from);
- for (ap = jp->to; ap != NULLLIST; ap = ap->next)
- tprintf (" %s", ap->val);
- tprintf ("\n");
- }
- }
-
- /* start sending that mail */
-
- execjobs ();
-
- /* Restart timer */
-
- start_timer(&Smtpcli_t);
- smtptick_running = 0;
- return;
- }
-
-
- static int should_enter_delay(struct smtpcli *cb)
- {
- resolve_mx (cb->destname);
- log(-1, "should_enter_delay: resolve_mx cb->destname = %x ", (void *)cb->destname); /* DEBUG */
- if (are_we_an_mx)
- return 1;
-
- return 0;
- }
-
-
- void delay_job(int32 msgid)
- {
- char t[20];
-
- if (Delaytime == 0)
- /* Not using SMTP delay */
- return;
-
- sprintf (t, "%lu", msgid);
-
- if (Smtptrace)
- tprintf ("Delivery Failed: adding job %s to delay queue\n", t);
-
- mlock_suffix (Mailqdir, t, "dly");
- }
-
- /* This is the master state machine that handles a single SMTP transaction.
- * It is called with a queue of jobs for a particular host.
- * The logic is complicated by the "Smtpbatch" variable, which controls
- * the batching of SMTP commands. If Smtpbatch is true, then many of the
- * SMTP commands are sent in one swell foop before waiting for any of
- * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
- * out there, so provisions have to be made to operate SMTP in lock-step mode.
- */
-
- static void __stdargs smtp_send (int unused, void *cb1, void *p)
- {
- struct smtpcli *cb;
- struct list *tp;
- struct sockaddr_in fsocket;
- char *cp;
- int rcode;
- int rcpts;
- int goodrcpt;
- int i;
- int init = 1;
-
- cb = (struct smtpcli *)cb1;
- cb->lock = 1;
- fsocket.sin_family = AF_INET;
- fsocket.sin_addr.s_addr = cb->ipdest;
- fsocket.sin_port = IPPORT_SMTP;
-
- cb->s = socket(AF_INET, SOCK_STREAM, 0);
- sockmode(cb->s, SOCK_ASCII);
- setflush(cb->s, -1); /* We'll explicitly flush before reading */
-
- if (Smtptrace)
- tprintf ("SMTP client Trying...\n");
-
- /* Run connect () under a timeout in case the destination is unreachable. */
-
- alarm(connect_wait_val);
- if (connect (cb->s, (char *) &fsocket, SOCKSIZE) == 0) {
- alarm (0L);
- if (Smtptrace)
- tprintf ("Connected\n");
- }
- else {
- alarm(0L);
- if (Delaytime && (cb->ipdest == Ip_addr || should_enter_delay(cb)))
- delay_job(atol(cb->jobq->jobname));
- else
- if (Gateway != 0L) {
-
- /* Try sending it via the gateway, as long as it's not for us. */
-
- if (Smtptrace)
- tprintf ("SMTP client Trying gateway...\n");
-
- close_s(cb->s);
- cb->ipdest = Gateway;
- fsocket.sin_addr.s_addr = Gateway;
- cb->s = socket(AF_INET, SOCK_STREAM, 0);
- sockmode(cb->s, SOCK_ASCII);
- setflush(cb->s, -1);
- alarm(connect_wait_val);
-
- if (connect(cb->s, (char *) &fsocket, SOCKSIZE) != 0) {
- alarm(0L);
- cp = sockerr(cb->s);
- if (Smtptrace)
- tprintf("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
- log(cb->s, "SMTP %s Connect failed: %s", psocket (&fsocket),
- cp != NULLCHAR ? cp : "");
-
- goto quit;
- }
- else {
- alarm(0L);
- if (Smtptrace)
- tprintf ("Connected to Gateway\n");
- }
-
- }
- else {
- cp = sockerr(cb->s);
- if (Smtptrace)
- tprintf ("Connect failed: %s\n", cp != NULLCHAR ? cp : "");
- log (cb->s, "SMTP %s Connect failed: %s", psocket(&fsocket),
- cp != NULLCHAR ? cp : "");
- goto quit;
- }
-
- }
-
- if (!Smtpbatch) {
- rcode = getresp (cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
-
- }
-
- /* Say HELO */
-
- sendcmd(cb, "HELO %s\n", Hostname);
-
- if (!Smtpbatch) {
- rcode = getresp(cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
- }
-
- do { /* For each message... */
- /* if this file open fails, skip it */
-
- if ((cb->tfile = fopen(cb->tname, READ_TEXT)) == NULLFILE)
- continue;
-
- /* Send MAIL and RCPT commands */
-
- sendcmd (cb, "MAIL FROM:<%s>\n", cb->jobq->from);
- if (!Smtpbatch) {
- rcode = getresp(cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
- }
-
- rcpts = 0;
- goodrcpt = 0;
- for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next) {
- sendcmd(cb, "RCPT TO:<%s>\n", tp->val);
- if (!Smtpbatch) {
- rcode = getresp (cb, 200);
- if (rcode == -1)
- goto quit;
-
- if (rcode < 400)
- goodrcpt = 1; /* At least one good */
- }
- rcpts++;
- }
-
- /* Send DATA command */
-
- sendcmd(cb, "DATA\n");
- if (!Smtpbatch) {
- rcode = getresp(cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
- }
-
- if (Smtpbatch) {
- /* Now wait for the responses to come back. The first time we
- * do this, we wait first for the start banner and HELO
- * response. In any case, we wait for the response to the MAIL
- * command here. */
-
- for (i = init ? 3 : 1; i > 0; i--) {
- rcode = getresp(cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
- }
- init = 0;
-
- /* Now process the responses to the RCPT commands */
-
- for (i = rcpts; i != 0; i--) {
- rcode = getresp (cb, 200);
- if (rcode == -1)
- goto quit;
-
- if (rcode < 400)
- goodrcpt = 1; /* At least one good */
-
- }
-
- /* And finally get the response to the DATA command. Some
- * servers will return failure here if no recipients are valid,
- * some won't. */
-
- rcode = getresp (cb, 200);
- if (rcode == -1 || rcode >= 400)
- goto quit;
-
- /* check for no good rcpt on the list */
-
- if (goodrcpt == 0) {
- sendcmd(cb, ".\n"); /* Get out of data mode */
- goto quit;
- }
- }
-
- /* Send the file. This also closes it */
-
- smtpsendfile(cb);
-
- /* Wait for the OK response */
- rcode = getresp(cb, 200);
- if (rcode == -1)
- goto quit;
-
- if ((rcode >= 200 && rcode < 300) || rcode >= 500) {
-
- /* if a good transfer or permanent failure remove job */
-
- if (cb->errlog != NULLLIST)
- retmail (cb);
-
- /* Unlink the textfile */
-
- (void) unlink (cb->tname);
- (void) unlink (cb->wname); /* unlink workfile */
-
- log(cb->s, "SMTP sent job %s To: %s From: %s",
- cb->jobq->jobname, cb->jobq->to->val, cb->jobq->from);
-
- if (smtpverbose != 0 && Smtptrace <= 1) {
- /* Show sending progress. */
-
- tprintf("Sent %s\n", cb->jobq->jobname);
- }
- }
-
- } while (next_job(cb));
-
- quit:
- sendcmd(cb, "QUIT\n");
- if (cb->errlog != NULLLIST) {
- retmail (cb);
- unlink (cb->wname); /* unlink workfile */
- unlink (cb->tname); /* unlink text */
- }
-
- close_s(cb->s);
- if (cb->tfile != NULLFILE)
- fclose(cb->tfile);
-
- cb->lock = 0;
- del_session(cb);
- }
-
-
- /* mlock - create mail lockfile */
-
- int mlock(char *dir, char *id)
- {
- return mlock_suffix (dir, id, "lck");
- }
-
-
- int mlock_suffix(char *dir, char *id, char *suffix)
- {
- char lockname[LINELEN];
- int fd;
-
- #if defined(MSDOS) || defined(ATARI)
- if (strlen (id) > 8) { /* truncate long filenames */
- id[8] = '\0';
- if (id[7] == '/')
- id[7] = '\0';
-
- }
- #endif
- /* Try to create the lock file in an atomic operation */
-
- sprintf(lockname, "%s/%s.%s", dir, id, suffix);
-
- if ((fd = open(lockname, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
- return -1;
-
- close(fd);
- return 0;
- }
-
-
- /* rmlock - Remove mail lockfile */
-
- int rmlock(char *dir, char *id)
- {
- return rmlock_suffix(dir, id, "lck");
- }
-
-
- int rmlock_suffix(char *dir, char *id, char *suffix)
- {
- char lockname[LINELEN];
-
- #if defined(MSDOS) || defined(ATARI)
- if (strlen (id) > 8) { /* truncate long filenames */
- id[8] = '\0';
- if (id[7] == '/')
- id[7] = '\0';
-
- }
- #endif
-
- sprintf (lockname, "%s/%s.%s", dir, id, suffix);
- return (unlink (lockname));
- }
-
-
- /* del_session - Free the message struct and data */
-
- static void del_session(struct smtpcli *cb)
- {
- int i;
- struct smtp_job *jp, *tp;
-
- if (cb == NULLSMTPCLI)
- return;
-
- for (i = 0; i < MAXSESSIONS; i++)
- if (cli_session[i] == cb) {
- cli_session[i] = NULLSMTPCLI;
- break;
- }
-
- log(-1,"del_session: free cb->wname = %x ", (void *)cb->wname); /* DEBUG */
- free(cb->wname);
- log(-1,"del_session: free cb->tname = %x ", (void *)cb->tname); /* DEBUG */
- free(cb->tname);
- log(-1,"del_session: free cb->destname = %x ", (void *)cb->destname); /* DEBUG */
- free(cb->destname);
-
- for (jp = cb->jobq; jp != NULLJOB; jp = tp) {
- tp = jp->next;
- del_job(jp);
- }
-
- del_list(cb->errlog);
- log(-1,"del_session: free cb = %x ", (void *)cb); /* DEBUG */
- free((void *)cb);
- Smtpsessions--; /* number of connections active */
- }
-
-
- /* del_job - Free smtp_job structure */
-
- static void del_job(struct smtp_job *jp)
- {
- if (*jp->jobname != '\0')
- (void) rmlock(Mailqdir, jp->jobname);
-
- log(-1,"del_job: free jp->from = %x ", (void *)jp->from); /* DEBUG */
- free(jp->from);
- del_list(jp->to);
- log(-1,"del_job: free jp = %x ", (void *)jp); /* DEBUG */
- free((void *)jp);
- }
-
-
- /* del_list - Delete a list of list structs */
-
- void del_list(struct list *lp)
- {
- struct list *tp, *tp1;
-
- for (tp = lp; tp != NULLLIST; tp = tp1) {
- tp1 = tp->next;
- log(-1, "del_list: free tp->val = %x ", (void *)tp->val); /* DEBUG */
- free(tp->val);
- log(-1, "del_list: free tp = %x ", (void *)tp); /* DEBUG */
- free((char *) tp);
- }
- }
-
-
- /* retmail - Stub for calling mdaemon to return message to sender */
-
- static void retmail(struct smtpcli *cb)
- {
- FILE *infile;
-
- if (Smtptrace > 5)
- tprintf("smtp job %s returned to sender\n", cb->wname);
-
- if ((infile = fopen(cb->tname, READ_TEXT)) == NULLFILE)
- return;
-
- mdaemon(infile, cb->jobq->from, cb->errlog, 1);
- fclose(infile);
- }
-
-
- /* lookup - Look to see if a smtp control block exists for this ipdest */
-
- static struct smtpcli *lookup(int32 destaddr)
- {
- int i;
-
- for (i = 0; i < MAXSESSIONS; i++) {
- if (cli_session[i] == NULLSMTPCLI)
- continue;
-
- if (cli_session[i]->ipdest == destaddr)
- return cli_session[i];
- }
- return NULLSMTPCLI;
- }
-
-
- /* newcb - create a new smtp control block */
-
- static struct smtpcli *newcb(void)
- {
- int i;
- struct smtpcli *cb;
-
- for (i = 0; i < MAXSESSIONS; i++) {
- if (cli_session[i] == NULLSMTPCLI) {
- cb = (struct smtpcli *) calloc(1, sizeof (struct smtpcli));
- log(-1,"newcb: calloc cb = %x ", (void *)cb); /*DEBUG */
- cb->wname = malloc((unsigned) strlen (Mailqdir) + JOBNAME);
- log(-1,"newcb: malloc cb->wname = %x ", (void *)cb->wname); /* DEBUG */
- cb->tname = malloc((unsigned) strlen (Mailqdir) + JOBNAME);
- log(-1,"newcb: malloc cb->tname = %x ", (void *)cb->tname); /* DEBUG */
- cli_session[i] = cb;
- Smtpsessions++; /* number of connections active */
-
- return (cb);
- }
- }
- return NULLSMTPCLI;
- }
-
-
- static void execjobs(void)
- {
- int i;
- struct smtpcli *cb;
-
- for (i = 0; i < MAXSESSIONS; i++) {
- cb = cli_session[i];
- if (cb == NULLSMTPCLI)
- continue;
-
- if (cb->lock)
- continue;
-
- sprintf(cb->tname, "%s/%s.txt", Mailqdir, cb->jobq->jobname);
- sprintf(cb->wname, "%s/%s.wrk", Mailqdir, cb->jobq->jobname);
-
- newproc("smtp_send", 1024, smtp_send, 0, cb, NULL, 0);
-
- if (Smtptrace)
- tprintf("Trying Connection to %s\n", inet_ntoa (cb->ipdest));
- }
- }
-
-
- /* smtp_job - Add this job to control block queue */
-
- static struct smtp_job *setupjob(struct smtpcli *cb, char *id, char *from)
- {
- struct smtp_job *p1, *p2;
-
- p1 = (struct smtp_job *) calloc(1, sizeof (struct smtp_job));
- log(-1, "setupjob: calloc p1 = %x ", (void *)p1); /* DEBUG */
-
- p1->from = strdup(from); /* implicit malloc */
- log(-1, "setupjob: strdup p1->from = %x ", (void *)p1->from); /* DEBUG */
- strcpy (p1->jobname, id);
-
- /* now add to end of jobq */
-
- if ((p2 = cb->jobq) == NULLJOB)
- cb->jobq = p1;
- else {
- while (p2->next != NULLJOB)
- p2 = p2->next;
-
- p2->next = p1;
- }
-
- return p1;
- }
-
-
- /* next_job - Called to advance to the next job */
-
- static int next_job(struct smtpcli *cb)
- {
- struct smtp_job *jp;
-
- jp = cb->jobq->next;
- del_job(cb->jobq);
-
- /* remove the error log of previous message */
-
- del_list(cb->errlog);
- cb->errlog = NULLLIST;
- cb->jobq = jp;
- if (jp == NULLJOB)
- return 0;
-
- sprintf(cb->tname, "%s/%s.txt", Mailqdir, jp->jobname);
- sprintf(cb->wname, "%s/%s.wrk", Mailqdir, jp->jobname);
-
- if (Smtptrace > 5)
- tprintf("sending job %s\n", jp->jobname);
-
- return 1;
-
- }
-
-
- /* mailroute - Mail routing function. */
-
- int32 mailroute(char *dest, int32 gateway)
- {
- int32 destaddr;
-
- /* Test for domain literal first. */
-
- if (*dest == '[')
- return (aton(dest));
-
- /* If the destination is this site, then *don't* go through a mail
- * server (MX site)
- */
-
- if (stricmp(dest, Hostname) == 0)
- if ((destaddr = resolve(dest)) != 0) {
- log(-1, "next_job: resolve destaddr = %x ", (void *)destaddr); /* DEBUG */
- return destaddr;
- }
- log(-1, "next_job: resolve destaddr = %x ", (void *)destaddr); /* DEBUG */
-
-
- /* look up address or use the gateway */
-
- destaddr = resolve_mx(dest);
- log(-1, "next_job: resolve_mx destaddr = %x ", (void *)destaddr); /* DEBUG */
-
- if (destaddr == 0 && (destaddr = resolve (dest)) == 0) {
- #ifdef DSERVER
- if (zone_filename (dest, NULL))
- destaddr = gateway;
- else
- #endif
- if (Gateway != 0)
- destaddr = Gateway; /* Use the gateway */
- }
-
- return destaddr;
- }
-
-
- /* logerr - Save line in error list */
-
- static void logerr(struct smtpcli *cb, char *line)
- {
- struct list *lp, *tp;
-
- tp = (struct list *)calloc(1, sizeof (struct list));
- log(-1, "logerr: calloc tp = %x ", (void *)tp); /* DEBUG */
- tp->val = strdup(line); /* implicit malloc */
- log(-1, "logerr: strdup tp->val = %x ", (void *)tp->val); /* DEBUG */
- /* find end of list */
- if ((lp = cb->errlog) == NULLLIST)
- cb->errlog = tp;
- else {
- while (lp->next != NULLLIST)
- lp = lp->next;
-
- lp->next = tp;
- }
- }
-
-
- static int smtpsendfile(struct smtpcli *cb)
- {
- int error = 0;
-
- strcpy(cb->buf, "\n");
-
- while (fgets (cb->buf, sizeof (cb->buf), cb->tfile) != NULLCHAR) {
-
- if (cb->buf[0] == '.') /* handle dot transparency */
- usputc(cb->s,'.'); /* add extra '.' */
-
- usputs (cb->s, cb->buf);
- }
-
- fclose(cb->tfile);
- cb->tfile = NULLFILE;
-
- /* Send the end-of-message command */
-
- if (cb->buf[strlen (cb->buf) - 1] == '\n')
- sendcmd(cb, ".\n");
- else
- sendcmd(cb, "\n.\n");
-
- return error;
- }
-
-
- /* sendcmd - Do a printf() on the socket with optional local tracing */
-
- static void sendcmd(struct smtpcli * cb, char *fmt,...)
- {
- va_list args;
-
- va_start(args, fmt);
- if (Smtptrace) {
- vsprintf(cb->buf, fmt, args);
- tprintf("smtp sent: %s", cb->buf);
- }
-
- vsprintf(cb->buf, fmt, args);
- usputs(cb->s, cb->buf);
- va_end(args);
- }
-
-
- /* getresp - Wait for, read & display server response. Return the result code. */
-
- static int getresp(struct smtpcli *cb, int mincode)
- {
- int rval;
- char line[LINELEN];
-
- usflush (cb->s);
- for (;;) {
- /* Get line */
- if (recvline(cb->s, line, LINELEN) == -1) {
- rval = -1;
- break;
- }
-
- rip(line); /* Remove cr/lf */
- rval = atoi(line);
-
- if (Smtptrace)
- tprintf("smtp recv: %s\n", line); /* Display to user */
-
- if (rval >= 500) { /* Save permanent error replies */
- char tmp[LINELEN];
-
- if (cb->errlog == NULLLIST) {
- sprintf(tmp, "While talking to %s:",
- cb->destname);
- logerr(cb, tmp);
- }
-
- if (cb->buf[0] != '\0') { /* save offending command */
- rip(cb->buf);
- sprintf(tmp, ">>> %s", cb->buf);
- logerr(cb, tmp);
- cb->buf[0] = '\0';
- }
-
- sprintf(tmp, "<<< %s", line);
- logerr(cb, tmp); /* save the error reply */
- }
-
- /* Messages with dashes are continued */
-
- if (line[3] != '-' && rval >= mincode)
- break;
- }
-
- return rval;
- }
-
-
- static int doverbose(int argc, char *argv[], void *p)
- {
- return setbool(&smtpverbose, "SMTP verbose mode", argc, argv);
- }
-
-
- unsigned long golden_ymdhms(long year, long month, long day, long hour, long minute, long second)
- {
- long result = 365L * year + day + 31L * (month - 1);
-
- if (month < 3)
- result += (year - 1L) / 4L - (75L * ((year - 1) / 100 + 1)) / 100L;
- else
- result = result - (40L * month + 230L) / 100L + year / 4L - (75L * (year / 100 + 1)) / 100L;
-
- result *= 86400L;
- result += 3600 * hour;
- result += 60 * minute;
- result += second;
-
- return result;
- }
-
-
- static int explock(char *dir, char *pre, char *suf, int32 age)
- {
- union FILE_TIME {
- struct ftime ft;
- unsigned int ft_int[2];
- } file_time;
-
- struct ffblk fileinfo;
- struct tm *tm_now;
- time_t t_now;
- char t[80];
- unsigned long now, fage, difference;
-
- sprintf(t, "%s/%s.%s", dir, pre, suf);
- if (findfirst (t, &fileinfo, 0) == -1)
- return 1;
-
- if (Delaytime == 0)
- return !unlink (t);
-
- t_now = time(NULL);
- tm_now = localtime(&t_now);
- now = golden_ymdhms(tm_now->tm_year + 1900, tm_now->tm_mon + 1,
- tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min,
- tm_now->tm_sec);
- file_time.ft_int[0] = fileinfo.ff_ftime;
- file_time.ft_int[1] = fileinfo.ff_fdate;
- fage = golden_ymdhms (file_time.ft.ft_year + 1980, file_time.ft.ft_month,
- file_time.ft.ft_day, file_time.ft.ft_hour, file_time.ft.ft_min,
- file_time.ft.ft_tsec * 2);
- difference = now - fage;
- if (difference >= Delaytime)
- return !unlink(t);
-
- return 0;
- }
-
-